from enum import IntEnum
from typing import List

from sqlalchemy import and_
from werkzeug.security import check_password_hash, generate_password_hash

from app.models import BaseModel
from app.models.classesModel import Classes
from tools import db

# 用户收藏表，建立用户与其收藏课件多对多的关系
tb_user_collection = db.Table(
    "api_user_collection",
    db.Column(
        "user_id",
        db.Integer,
        db.ForeignKey("api_user.id", ondelete="CASCADE", onupdate="CASCADE"),
    ),
    db.Column(
        "courseware_id",
        db.Integer,
        db.ForeignKey("api_courseware.id", ondelete="CASCADE", onupdate="CASCADE"),
    ),
)

# 用户课程表，建立用户与课程多对多的关系
tb_user_course = db.Table(
    "api_user_course",
    db.Column(
        "user_id",
        db.Integer,
        db.ForeignKey("api_user.id", ondelete="CASCADE", onupdate="CASCADE"),
    ),
    db.Column(
        "course_id",
        db.String(32),
        db.ForeignKey("api_course.id", ondelete="CASCADE", onupdate="CASCADE"),
    ),
)

# 用户红蓝组，建立用户与攻守方多对多的关系
tb_user_team = db.Table(
    "apt_red_blue_group",
    db.Column(
        "user_id",
        db.Integer,
        db.ForeignKey("api_user.id", ondelete="CASCADE", onupdate="CASCADE"),
        # primary_key=True
    ),
    db.Column(
        "group_id",
        db.Integer,
        db.ForeignKey(
            "api_ctf_red_blue_group.id", ondelete="CASCADE", onupdate="CASCADE"
        ),
        # primary_key=True
    ),
)


class User(db.Model, BaseModel):

    __tablename__ = "api_user"

    # TODO: 删除这里和role_id
    class RoleChoices(IntEnum):
        teachers = 1  # 教师
        student = 0  # 学生
        rb_referee = 2  # 红蓝裁判
        rb_pilot = 3  # 红蓝导调
        audience = 4  # 观众

    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    username = db.Column(db.String(120), unique=True)
    account_name = db.Column(db.String(120))
    email = db.Column(db.String(120), unique=True)
    password_hash = db.Column(db.String(130))
    project_id = db.Column(db.String(130), index=True)
    role_id = db.Column(db.Integer, index=True)
    is_superuser = db.Column(db.Boolean, default=False)
    class_id = db.Column(db.Integer, db.ForeignKey(Classes.id))

    # 当前用户收藏的所有课件
    collection_courseware = db.relationship(
        "Courseware", secondary=tb_user_collection, lazy="dynamic"
    )
    # 当前用户的课程
    courses = db.relationship(
        "Course", secondary=tb_user_course, backref="relate_user", lazy="dynamic"
    )

    # 用户红蓝归属
    groups = db.relationship(
        "CtfRedBlueGroup", secondary=tb_user_team, backref="relate_user", lazy="dynamic"
    )

    # 用户红蓝得分
    red_blue_score_record = db.relationship(
        "LinkCtfRedBlueScoreInfo", uselist=True, backref=db.backref("relate_user")
    )

    @property
    def password(self):
        raise AttributeError("password is not a readable attribute")

    @password.setter
    def password(self, password):
        self.password_hash = generate_password_hash(password)

    def verify_password(self, password):
        return check_password_hash(self.password_hash, password)

    def to_dict(self):
        return {
            "id": self.id,
            "username": self.username,
            "realname": self.account_name,
            "email": self.email,
            "collection_courseware": self.collection_courseware.count(),
            "course_count": self.courses.count(),
            "role_id": self.role_id,
        }

    def check_user_role(self, role_id: int = None, role_name: str = None):
        """确定用户是否拥有某角色权限"""
        from app.models.roleModel import Role, UserRole

        if not role_id and not role_name:
            raise ValueError("缺少定位角色参数")

        _join_filter = [UserRole.role_id == Role.id]
        if role_id:
            _join_filter.append(Role.id == role_id)
        if role_name:
            _join_filter.append(Role.name == role_name)

        _select = UserRole.query.join(Role, and_(*_join_filter)).filter(
            UserRole.user_id == self.id
        )
        return db.session.query(_select).scalar()

    @property
    def roles(self):
        from app.models.roleModel import Role, UserRole

        # 仅返回启用角色
        return set(
            Role.query.join(
                UserRole, and_(UserRole.role_id == Role.id, UserRole.user_id == self.id)
            )
            .filter(Role.is_enabled == 1)
            .all()
        )

    @roles.setter
    def roles(self, role_list: List):
        from app.models.roleModel import Role, UserRole

        current_roles = {val.id for val in self.roles}

        if all(map(lambda x: type(x) is Role, role_list)):  # noqa
            role_list = {val.id for val in role_list}

        # 删除不存在的角色关系
        diff = current_roles - set(role_list)
        UserRole.query.filter(
            UserRole.role_id.in_(diff), UserRole.user_id == self.id
        ).delete()
        # 获取新增角色
        _role_list = role_list - current_roles

        user_roles = []
        for val in _role_list:
            user_roles.append(UserRole(user_id=self.id, role_id=val))
        db.session.add_all(user_roles)
